/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.editor.ext;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.File;
import org.netbeans.editor.Analyzer;
/**
* Management of storage of the data for the java completion.
*
* @author Miloslav Metelka
* @version 1.00
*/
public class FileStorage {
/** Constant for checking the maximum size of the string.
* If the string size exceeds this value the error is thrown
* as there's very likely corruption of the file.
*/
private static final int MAX_STRING = 60000;
private static final int BYTES_INCREMENT = 2048;
private static final byte[] EMPTY_BYTES = new byte[0];
File file;
boolean openedForWrite;
/** File descriptor */
RandomAccessFile raf;
/** Current offset in the bytes array */
int offset;
/** Byte array holding the data that were read from file */
byte[] bytes = EMPTY_BYTES;
/** Shared char array to use for reading strings */
char[] chars = Analyzer.EMPTY_CHAR_ARRAY;
/** String cache */
StringCache strCache;
/** @param fileName name of file to operate over
*/
public FileStorage(String fileName) {
this(fileName, new StringCache());
}
public FileStorage(String fileName, StringCache strCache) {
file = new File(fileName);
this.strCache = strCache;
}
public void open(boolean requestWrite) throws IOException {
if (raf != null) {
if (openedForWrite == requestWrite) {
raf.seek(file.length());
return; // already opened with correct type
} else { // opened with different type
close();
}
}
if (requestWrite) { // check existency
if (!file.exists()) {
file.createNewFile();
}
}
// open the file
raf = new RandomAccessFile(file, requestWrite ? "rw" : "r"); // NOI18N
raf.seek(file.length());
openedForWrite = requestWrite;
}
public void close() throws IOException {
if (raf != null) {
raf.close();
raf = null;
}
}
/** Check size of bytes[] array */
private void checkBytesSize(int len) {
if (bytes.length < len) {
byte[] newBytes = new byte[len + BYTES_INCREMENT];
System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
bytes = newBytes;
}
}
/** Read some part of the file into the begining of bytes array
* and reset offset to zero.
*/
public void read(int len) throws IOException {
checkBytesSize(len);
raf.readFully(bytes, 0, len);
offset = 0;
}
/** Write bytes array (with offset length) to the file */
public void write() throws IOException {
if (offset > 0) {
raf.write(bytes, 0, offset);
}
offset = 0;
}
public void seek(int filePointer) throws IOException {
raf.seek(filePointer);
}
public String getFileName() {
return file.getAbsolutePath();
}
public int getFilePointer() throws IOException {
return (int)raf.getFilePointer();
}
public void setOffset(int offset) {
this.offset = offset;
}
public int getOffset() {
return offset;
}
public int getFileLength() throws IOException {
return (int)file.length();
}
public void resetBytes() {
bytes = EMPTY_BYTES;
}
/** Reset the size of the file and set current offset to zero. */
public void resetFile() throws IOException {
open(true);
offset = 0;
raf.setLength(0);
close();
}
/** Get the integer value from the bytes[] array */
public int getInteger() {
int i = bytes[offset++];
i = (i << 8) + (bytes[offset++] & 255);
i = (i << 8) + (bytes[offset++] & 255);
i = (i << 8) + (bytes[offset++] & 255);
return i;
}
/** Get the string value from the bytes[] array */
public String getString() {
int len = getInteger(); // length of string
if (len < 0) {
if (len == -1) {
return null;
} else { // consistency error
throw new Error("Consistency error: read string length=" + len); // NOI18N
}
}
if (len > MAX_STRING) {
throw new Error("FileStorage: String len is " + len // NOI18N
+ ". There's probably a corruption in the file '" // NOI18N
+ getFileName() + "'."); // NOI18N
}
if (chars.length < len) { // check chars array size
chars = new char[2 * len];
}
for (int i = 0; i < len; i++) {
chars[i] = (char)((bytes[offset] << 8) + (bytes[offset + 1] & 255));
offset += 2;
}
String s = null;
if (len >= 0) {
if (strCache != null) {
s = strCache.getString(chars, 0, len);
} else { // no string cache
s = new String(chars, 0, len);
}
}
return s;
}
/** Put the integer into bytes[] array. It is stored as four bytes
* in big endian.
*/
public void putInteger(int i) {
checkBytesSize(offset + 4); // int size
bytes[offset + 3] = (byte)(i & 255);
i >>>= 8;
bytes[offset + 2] = (byte)(i & 255);
i >>>= 8;
bytes[offset + 1] = (byte)(i & 255);
i >>>= 8;
bytes[offset] = (byte)i;
offset += 4;
}
/** Put the string into bytes[] array. First the length is stored
* by putInteger() and then all the characters as two bytes each in big
* endian.
*/
public void putString(String s) {
if (s == null) {
putInteger(-1);
return;
}
int len = s.length();
putInteger(len);
if (len > 0) {
checkBytesSize(offset + len * 2);
for (int i = 0; i < len; i++) {
char ch = s.charAt(i);
bytes[offset + 1] = (byte)(ch & 255);
ch >>>= 8;
bytes[offset] = (byte)(ch & 255);
offset += 2;
}
}
}
}
/*
* Log
* 6 Gandalf 1.5 1/13/00 Miloslav Metelka Localization
* 5 Gandalf 1.4 11/14/99 Miloslav Metelka
* 4 Gandalf 1.3 11/8/99 Miloslav Metelka
* 3 Gandalf 1.2 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 2 Gandalf 1.1 7/20/99 Miloslav Metelka
* 1 Gandalf 1.0 6/8/99 Miloslav Metelka
* $
*/